package main

import (
	_ "errors"
	"fmt"
	_ "time"
)

// go 语言的数组默认是值传递，拷贝值
// 但是slice传递的就是地址本身,这点和数组有着本质的区别
func test(arr [3]int) {
	arr[0] = 9
	arr[1] = 9
	arr[2] = 9
}

func main() {
	// slice 切片是一个结构体
	// 类似java中的ArrayList
	// type slice struct {
	// 	 ptr *type // 指针
	// 	 len int // 长度
	// 	 cap int //容量，一般是底层数组的1.5倍，但不一定
	// }

	// 1. 创建 slice
	//1.1 引用一个数组
	numArr01 := [6]int{1, 2, 3, 4, 5, 6}
	//numSlice01 := numArr01[1:] //表示[1,len(arr)) // 取得索引1及其以后的
	//numSlice01 := numArr01[:x] //表示获取得索引[0,x)范围的元素 x 最大是 len(arr)
	//numSlice01 := numArr01[:] // 表示截取整个数组
	numSlice01 := numArr01[1:3]                        // 取得下标[1,3)的元素值,实际上是指针指向数组的下标为1的位置，注意：结束索引必须大于开始索引，否则报错
	fmt.Printf("numSlice01 类型 = %T \n", numSlice01)    // numSlice01 类型 = []int
	fmt.Println("&numArr01[1] = ", &numArr01[1])       // &numArr01[1] =  0xc000072038
	fmt.Println("&numSlice01[0] = ", &numSlice01[0])   // &numSlice01[0] =  0xc000072038
	fmt.Println("numSlice01 = ", numSlice01)           // numSlice01 =  [2 3]
	fmt.Println("len(numSlice01) = ", len(numSlice01)) //len(numSlice01) =  2
	fmt.Println("cap(numSlice01) = ", cap(numSlice01)) //len(numSlice01) =  5
	// fmt.Println("&numSlice01[0] = ", &numSlice01[2]) // 报错数组下标越界，因为本质上slice还是一个指针指向了数组

	fmt.Println("~~~ 分割线 ~~~")
	//1.2 使用make([] type, len, cap)创建
	numSlice02 := make([]int, 3, 6)
	fmt.Println("numSlice02 = ", numSlice02)           //numSlice02 =  [0 0 0]
	fmt.Println("len(numSlice02) = ", len(numSlice02)) //len(numSlice02) =  3
	fmt.Println("cap(numSlice02) = ", cap(numSlice02)) //cap(numSlice02) =  6

	fmt.Println("~~~ 分割线 ~~~")
	//1.3 直接创建
	numSlice03 := []int{1, 2, 3}
	fmt.Println("numSlice03 = ", numSlice03)           //numSlice03 =  [1 2 3]
	fmt.Println("len(numSlice03) = ", len(numSlice03)) //len(numSlice03) =  3
	fmt.Println("cap(numSlice03) = ", cap(numSlice03)) //cap(numSlice03) =  3

	fmt.Println("~~~ 分割线 ~~~")

	// 2. 遍历和数组一样
	for i := 0; i < len(numSlice03); i++ {
		fmt.Printf("numSlice03[%v] = %v ,", i, numSlice03[i])
	}
	fmt.Println("")
	for i, v := range numSlice03 {
		fmt.Printf("numSlice03[%v] = %v ,", i, v)
	}
	fmt.Println("~~~ 分割线 ~~~")

	// 3. 切片再切片
	numSlice04 := numSlice03[1:2] // 切片再切片，此时改变numSlice04的值会影响numSlice03，因为都是指针在引用

	// 4. 追加数据,slice初始化的时候是一个数组，不能通过下标进行直接赋值否则报数组下标越界错误
	// 内建函数append将元素追加到切片的末尾。若它有足够的容量，其目标就会重新切片以容纳新的元素。
	// 否则，就会分配一个新的基本数组。append返回更新后的切片，因此必须存储追加后的结果。
	// func append(slice []Type, elems ...Type) []Type
	fmt.Println("追加前 numSlice04 = ", numSlice04) //追加前 numSlice04 =  [2]
	numSlice05 := append(numSlice04, 7, 8, 9)
	fmt.Println("追加后 numSlice04 = ", numSlice04) //追加后 numSlice04 =  [2]
	fmt.Println("numSlice05 = ", numSlice05)     //numSlice05 =  [2 7 8 9]
	// 对 numSlice05赋值
	numSlice05[0] = 99
	fmt.Printf("赋值后 numSlice05[0] = %v， numSlice04[0] = %v\n", numSlice05[0], numSlice04[0])
	//赋值后 numSlice05[0] = 99， numSlice04[0] = 2
	// 我们发现并没有改变numSlice04的值，因为append函数返回了一个新的数组

	// 5. copy 返回的也是一个新数组
	// func copy(dst, src []Type) int
	// 内建函数copy将元素从来源切片复制到目标切片中，也能将字节从字符串复制到字节切片中。
	// copy返回被复制的元素数量，它会是 len(src) 和 len(dst) 中较小的那个。来源和目标的底层内存可以重叠。
	var arr01 []int = []int{0, 1, 2}
	var arr02 []int = make([]int, 3, 6)
	res := copy(arr02, arr01)
	fmt.Printf("arr01 = %v, arr02 = %v, res = %v \n", arr01, arr02, res)
	arr02[0] = 999 // 不会改变arr01的值因为值拷贝并返回了一个新的数组
	fmt.Printf("arr01 = %v, arr02 = %v \n", arr01, arr02)

}
